/*!
    \file  tcp_client.c
    \brief TCP client demo program 
*/

/*
    Copyright (C) 2016 GigaDevice

    2016-10-19, V1.0.0, demo for GD32F4xx
*/

#include "tcp_client.h"  
#include "lwip/tcp.h"
#include "lwip/memp.h"
#include <string.h>
#include <stdio.h>
#include "gd32f4xx.h"
#include "main.h"

#define MAX_BUF_SIZE    50

struct recev_packet 
{
    int length;
    char bytes[MAX_BUF_SIZE];
};

static err_t tcp_client_connected(void *arg, struct tcp_pcb *pcb, err_t err);
static err_t tcp_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);

/*!
    \brief      called when a data is received on the tcp connection 
    \param[in]  arg: the user argument
    \param[in]  pcb: the tcp_pcb that has received the data
    \param[in]  p: the packet buffer
    \param[in]  err: the error value linked with the received data
    \param[out] none
    \retval     err_t: error value
*/ 
static err_t tcp_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
    struct pbuf *q;
    struct recev_packet *recev_packet = (struct recev_packet *)arg;
    int buf_full;
    char *c;
    int i;

    /* we perform here any necessary processing on the pbuf */
    if (p != NULL){    
        /* we call this function to tell the LwIp that we have processed the data */
        /* this lets the stack advertise a larger window, so more data can be received*/
        tcp_recved(pcb, p->tot_len);

        /* check the name if NULL, no data passed, return withh illegal argument error */
        if(!recev_packet){ 
            pbuf_free(p);
            return ERR_ARG;
        }

        buf_full = 0;
        
        for(q=p; q != NULL; q = q->next){ 
          
            c = q->payload;
            for(i=0; i<q->len && !buf_full; i++){
                /* if the received data size is larger than the size we want to get */
                if(recev_packet->length < MAX_BUF_SIZE){ 
                    recev_packet->bytes[recev_packet->length] = c[i];
                    recev_packet->length++;
                }else{
                    buf_full = 1;
                }
            } 
        }      
      
        /* send out the message */
        tcp_write(pcb, recev_packet->bytes, recev_packet->length, 1);       
        recev_packet->length = 0;

        pbuf_free(p);
        
    }else if(ERR_OK == err){  
      
        mem_free(recev_packet);
        return tcp_close(pcb);
    }
  
    return ERR_OK;
}

/*!
    \brief      this function when the connection is established 
    \param[in]  arg: user supplied argument
    \param[in]  pcb: the tcp_pcb which accepted the connection
    \param[in]  err: error value
    \param[out] none
    \retval     err_t: error value
*/
static err_t tcp_client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
    tcp_arg(pcb, mem_calloc(sizeof(struct recev_packet), 1));
    /* configure LwIP to use our call back functions */
    tcp_recv(pcb, tcp_client_recv);

    return ERR_OK;  
}

/*!
    \brief      initialize the tcp_client application
    \param[in]  none
    \param[out] none
    \retval     none
*/

void tcp_client_init(void)
{
    struct tcp_pcb *pcb;
    struct ip_addr ipaddr;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);
  
    /* create a new TCP control block  */
    pcb = tcp_new();

    /* assign to the new pcb a local IP address and a port number */
    /* using IP_ADDR_ANY allow the pcb to be used by any local interface */
    if(ERR_USE != tcp_bind(pcb, IP_ADDR_ANY, 10262)){
        /* Specify the function to be called when a connection is established */    
        tcp_connect(pcb, &ipaddr, 10262, tcp_client_connected);
    }else{
        printf("connect is still alive \r\n ");
        memp_free(MEMP_TCP_PCB, pcb);
    }       
    
}
